#include "string_ex.h"
#include "string.h"
#include "math.h"

/*----------------------------------------------------配置部分----------------------------------------------------------*/
/*
    该库为变量转字符串的库，轻量级
    为了减少内存和性能消耗尽量不要开启下面的宏
    该库对于浮点数的处理会丢失一定精度，要不丢失精度还是使用标准库的sprintf
*/

#define USE_INT_64_WIDTH     0        // 是否使用整形宽度为 64 位 0-不使用 1-使用
#define USE_FLOAT_FULL_WIDTH 0        // 是否使用float完整输出 0-不使用 1-使用（不使用当浮点值比较大时会报overflow）

/*----------------------------------------------轻量级变量转字符串输出----------------------------------------------------*/
// 用户不要修改下面的代码
#define FLOAT_IS_NAN(x) ((x) != (x))
// #define FLOAT_IS_INF(x) ((x) == (1.0f / 0.0f) || (x) == (-1.0f / 0.0f))
#define FLOAT_IS_INF(x) (((*(uint32_t*)&(x)) & 0x7FFFFFFF) == 0x7F800000)
// 0x7F800000是IEEE754单精度浮点数正无穷大的二进制表示（指数位全1，尾数位全0）

// 定义使用多少位宽度的整型变量转字符串输出
#if (USE_FLOAT_FULL_WIDTH == 1 || USE_INT_64_WIDTH == 1)
#define DEF_STR_INT_WIDTH 64
#else
#define DEF_STR_INT_WIDTH 32
#endif

#if (DEF_STR_INT_WIDTH == 64)
// uint64 其最大值用十进制表示时共有 20 位数字。
#define str_uint_t uint64_t
#define str_int_t  int64_t
#else
// uint32 其最大值用十进制表示时共有 10 位数字。
#define str_uint_t uint32_t
#define str_int_t  int32_t
#endif

// 十六进制输出缓冲区要求大小
#define FLOAT_TO_STR_HEX_BUF_SIZE 24
#define UINT_TO_STR_HEX_BUF_SIZE  24

// 十进制输出缓冲区要求大小
#define UINT_TO_STR_DEC_BUF_SIZE  24
#define FLOAT_TO_STR_DEC_BUF_SIZE 24

#define HEX_CODE_STR "0123456789ABCDEF"
#define DEC_CODE_STR "0123456789"

#define INT_MAX_VALUE 2147483647
#define INT_MIN_VALUE -2147483648

static const char hex_chars[16] = HEX_CODE_STR;
static const char dec_char[10]  = DEC_CODE_STR;
/**
 * @brief 浮点型变量转字符串十六进制输出，输出格式为: 0xXXXXXXXXX
 * @param num 浮点型变量
 * @param buf 输出缓存区
 * @param buf_size 输出缓存区大小
 * @return char* 输出缓存区指针
 */
char* float_to_str_hex(float num, char* buf, uint8_t buf_size)
{
    uint8_t* hex_idx = (uint8_t*)&num;
    uint8_t  i       = 0;
    // uint8_t byte = 0;
    //  if (buf == NULL || buf_size < 12)
    //  {
    //      return NULL;
    //  }
    //  最小缓冲区要求: "0x" + 8个字符 + 终止符 = 11字节
    if (buf == NULL || buf_size < FLOAT_TO_STR_HEX_BUF_SIZE)
    {
        return NULL;
    }

    buf[0] = '0';
    buf[1] = 'x';
    for (i = 0; i < 4; i++)
    {
        // byte = hex_idx[3 - i];
        //  直接访问原始内存，大端序处理
        // buf[2 + i * 2] = hex_chars[byte >> 4];
        // buf[3 + i * 2] = hex_chars[byte & 0x0F];
        buf[2 + i * 2] = hex_chars[hex_idx[3 - i] >> 4];
        buf[3 + i * 2] = hex_chars[hex_idx[3 - i] & 0x0F];
    }
    buf[10] = '\0';
    return buf;
}

/**
 * @brief 整型变量转字符串十六进制输出，输出格式为: 0xXXXXXXXXX
 * @param num 整型变量
 * @param buf 输出缓存区
 * @param buf_size 输出缓存区大小
 * @return char* 输出缓存区指针
 * @note 自适应输出宽度 1字节 2字节 4字节
 */
char* uint_to_str_hex(str_uint_t num, char* buf, uint8_t buf_size)
{
    uint8_t hex_width = 2;
    uint8_t i         = 0;
    uint8_t shift     = 0;
    // 最小缓冲区要求: "0x" + 8个字符 + 终止符 = 11字节
    // if (buf == NULL || buf_size < 12)
    // {
    //     return NULL;
    // }
    if (buf == NULL || buf_size < UINT_TO_STR_HEX_BUF_SIZE)
    {
        return NULL;
    }

#if (DEF_STR_INT_WIDTH == 64)
    if (num > 0xFFFFFFFFFFFFFF)
        hex_width = 16;
    else if (num > 0xFFFFFFFFFFFF)
        hex_width = 14;
    else if (num > 0xFFFFFFFFFF)
        hex_width = 12;
    else if (num > 0xFFFFFFFF)
        hex_width = 10;
    else if (num > 0xFFFFFF)
        hex_width = 8;
    else if (num > 0xFFFF)
        hex_width = 6;
    else if (num > 0xFF)
        hex_width = 4;
    else
        hex_width = 2;        // 最小宽度为 2

#else
    if (num > 0xffffff)
        hex_width = 8;
    else if (num > 0xffff)
        hex_width = 6;
    else if (num > 0xff)
        hex_width = 4;
#endif

    // 写入前缀
    buf[0] = '0';
    buf[1] = 'x';

    for (i = 0; i < hex_width; i++)
    {
        shift      = (hex_width - 1 - i) * 4;
        buf[i + 2] = hex_chars[(num >> shift) & 0x0F];
    }

    buf[i + 2] = '\0';

    return buf;
}

/**
 * @brief 整型变量转字符串十进制输出，输出格式为: 0xXXXXXXXXX
 * @param num 整型变量
 * @param buf 输出缓存区
 * @param buf_size 输出缓存区大小
 * @return char* 输出缓存区指针
 * @note 自适应输出宽度 根据十进制位数输出
 */
char* uint_to_str_dec(str_uint_t num, char* buf, uint8_t buf_size)
{
    // 用于存储逆序数字的临时缓冲区

    char* buf_ptr = NULL;
    // 检查缓冲区是否足够大（最大数值需要10个字符 + 终止符）
    // if (buf == NULL || buf_size < 12)
    // {
    //     return NULL;
    // }
    if (buf == NULL || buf_size < UINT_TO_STR_DEC_BUF_SIZE)
    {
        return NULL;
    }

    buf_ptr  = buf + buf_size - 1;        // 指向缓冲区末尾
    *buf_ptr = '\0';                      // 初始化字符串结束符
    do
    {
        *(--buf_ptr) = dec_char[num % 10];        // 取最后一位数字并转换为字符
        num /= 10;
    } while (num > 0);        // 逐渐转换至结束
    return buf_ptr;
}

/**
 * @brief 有符号整型变量转字符串十进制输出，输出格式为: 0xXXXXXXXXX
 * @param num 整型变量
 * @param buf 输出缓存区
 * @param buf_size 输出缓存区大小
 * @return char* 输出缓存区指针
 * @note 自适应输出宽度 根据十进制位数输出，支持负数
 */
char* int_to_str_dec(str_int_t num, char* buf, uint8_t buf_size)
{
    char* end_buf = NULL;
    if (num < 0)
    {
        // 负数处理，先转换为正数，再添加负号
        end_buf      = uint_to_str_dec(-num, buf, buf_size);
        *(--end_buf) = '-';
    }
    else
    {
        end_buf = uint_to_str_dec(num, buf, buf_size);
    }
    return end_buf;
}

/**
 * @brief 浮点型变量转字符串十进制输出，输出格式为: 0.000000
 * @param num 浮点型变量
 * @param buf 输出缓存区
 * @param buf_size 输出缓存区大小
 * @param point_num 小数点位数，最大支持6位
 * @return char* 输出缓存区指针
 */
char* float_to_str_dec(float num, char* buf, uint8_t buf_size, uint8_t point_num)
{
    char      temp_int_buf[UINT_TO_STR_DEC_BUF_SIZE] = {0};        // 临时存储整数部分的缓冲区，最大支持16位整数
    char*     end_buf                                = NULL;
    uint8_t   buf_idx                                = 0;
    uint8_t   i                                      = 0;
    uint8_t   digit                                  = 0;
    str_int_t integer                                = 0;
    float     fraction                               = 0;

    /* 参数校验：缓冲区需要足够容纳整数10位+小数点+小数位数+终止符 */
    // if (buf == NULL || buf_size < (12 + point_num))
    // {
    //     return NULL;
    // }

    if (buf == NULL || buf_size < FLOAT_TO_STR_DEC_BUF_SIZE)
    {
        return NULL;
    }

    /*-----------------------浮点数有效性----------------------*/
    if (FLOAT_IS_NAN(num))
    {
        strcpy(buf, "nan");
        return buf;
    }
    else if (FLOAT_IS_INF(num))
    {
        strcpy(buf, "inf");
        return buf;
    }

#if (USE_FLOAT_FULL_WIDTH == 0)
    // 浮点数整数部分大于了int类型表示的范围
    if (num >= (float)INT_MAX_VALUE || num <= (float)INT_MIN_VALUE)
    {
        strcpy(buf, "overflow");
        return buf;
    }
#endif

    // 取出整数部分
    integer = (str_int_t)num;
    // 转换整数部分（复用已有带符号转换函数）
    end_buf = int_to_str_dec(integer, temp_int_buf, sizeof(temp_int_buf));
    // 复制整数部分到输出缓冲区
    buf_idx = strlen(end_buf);
    memcpy(buf, end_buf, buf_idx);

    // 0位小数点
    if (point_num == 0)
    {
        buf[buf_idx] = '\0';
        return buf;
    }

    // 添加小数点
    buf[buf_idx++] = '.';

    // 处理小数部分
    if (point_num > 6)
    {
        point_num = 6;
    }
    fraction = num - integer;        // 提取小数部分
    if (fraction < 0)
    {
        fraction = -fraction;
    }        // 处理负数的余数

    // 逐位提取小数
    for (i = 0; i < point_num; i++)
    {
        fraction *= 10;                          // 乘以10，准备提取下一位
        digit = (uint8_t)fraction;               // 提取整数部分
        fraction -= digit;                       // 移除已提取的整数部分
        buf[buf_idx++] = dec_char[digit];        // 转换为字符并存储
    }
    buf[buf_idx] = '\0';        // 添加字符串结束符
    return buf;
}
